#include <memory/spw_uni_ptr.h>
#include <gtest/gtest.h>

#include <memory>
#include <type_traits>

using namespace spwstd;
using namespace spwstd::spwptr;

static int basetest = 0;
class Base{
public:
    Base(){ basetest++; }
    Base(int base, int base2, int base3): base_(base), base2_(base2), base3_(base3){}
    ~Base(){ basetest--; }
    int base_;
    int base2_;
    int base3_;
};

class Derived:public Base{};

struct BaseDelete{
    BaseDelete(int v = 111): dvaule(v){}
    int dvaule;

    void operator()(Base* ptr){
        dvaule = 222;
        delete ptr;
    }
};
struct BaseArrDelete{
    BaseArrDelete(int v = 111): dvaule(v){}
    int dvaule;

    void operator()(Base* ptr){
        dvaule = 222;
        delete [] ptr;
    }
};

struct DerivedDelete : BaseDelete{
    using Pointer = int*;
    void operator()(int* ptr){
        delete ptr;
    }
    bool operator==(const DerivedDelete&) const { return true; }
};

struct IntDelete {
    using Pointer = int*;
    void operator()(int* ptr){
        delete ptr;
    }
};

struct DIntDelete: IntDelete { };

class UniquePtrTest : public testing::Test {
protected:
    static void SetUpTestCase() {
        std::cout << "xxxxxxxxxxx "<< __func__ << "SetUpTestCase xxxxxxxxxxxxx" << std::endl;
    }

    static void TearDownTestCase() {
        std::cout << "xxxxxxxxxxx " << __func__ << " TearDownTestCase xxxxxxxxxx" << std::endl;
    }

    virtual void SetUp() override {
        std::cout << "-----------"<< __func__ << " setup-----------" << std::endl; 
    }

    virtual void TearDown() override {
        std::cout << "-----------" << __func__ << " teardown-----------" << std::endl; 
    }

public:
    UniquePtr<Base> uniqueptr_test;
    UniquePtr<Base[]> uniqueptr_arr_test;
};

TEST_F(UniquePtrTest, ConstructTest) {
    // 默认构造和参数是nullptr
    UniquePtr<Base> nul(nullptr);
    EXPECT_TRUE(nul.Get() == uniqueptr_test.Get());
    EXPECT_TRUE(nul.Get() == UniquePtr<Base>::Pointer());
    EXPECT_TRUE( (std::is_same<decltype(nul.GetDeleter()),
                         decltype(uniqueptr_test.GetDeleter())>::value) );
    EXPECT_TRUE( (std::is_same<decltype(nul.GetDeleter()),
                         DefaultDelete<Base>&>::value) );
    {
        UniquePtr<Base> con1(new Base); // basetest = 1;
        EXPECT_TRUE(basetest == 1);
        UniquePtr<Base, DerivedDelete> con2(new int(111));  // BaseDelete::pointer = int*
        EXPECT_TRUE(basetest == 1);
    }

    EXPECT_TRUE(basetest == 0);

    // Deletetype为普通非引用类型或左值引用
    BaseDelete norefer;
    {
       UniquePtr<Base, BaseDelete> con3(new Base, norefer);
       EXPECT_TRUE(basetest == 1);
       EXPECT_TRUE(norefer.dvaule == 111);
       {
           UniquePtr<Base, BaseDelete&> con4(new Base, norefer);
           EXPECT_TRUE(basetest == 2);
       }
       EXPECT_TRUE(norefer.dvaule == 222);
    }
    EXPECT_TRUE(basetest == 0);
    // Delete为右值
    {
        UniquePtr<Base, BaseDelete> con5(new Base, BaseDelete());
        EXPECT_TRUE(basetest == 1);
    }
    EXPECT_TRUE(basetest == 0);
    // 移动
    {
        UniquePtr<Base, BaseDelete> con6(new Base, BaseDelete());
        EXPECT_TRUE(basetest == 1);
        UniquePtr<Base, BaseDelete> con7(spwuti::move(con6));
        EXPECT_TRUE(basetest == 1);
    }
    // 转换
    {
        // 和Testtype没什么关系, DerivedDelete::Pointer为int*
        // 所以ptr类型int*
        // DIntDelete可以隐式转化成IntDelete
        struct Testtype;
        UniquePtr<Testtype, DIntDelete> con8(new int(111));
        UniquePtr<int,IntDelete> con9(spwuti::move(con8));
    }

    // operator
    {
        UniquePtr<Base> con10(new Base);
        EXPECT_TRUE(basetest == 1);
        con10 = nullptr;
        EXPECT_TRUE(basetest == 0);
        UniquePtr<Base> con11(new Base);
        EXPECT_TRUE(basetest == 1);
        con10 = spwuti::move(con11);
        EXPECT_TRUE(basetest == 1);

        struct Testtype;
        UniquePtr<Testtype, DIntDelete> con12(new int(111));
        UniquePtr<int,IntDelete> con13;
        con13 = spwuti::move(con12);
        EXPECT_TRUE(con13);
    }
}

struct T{
    int t = 1111;
};

TEST_F(UniquePtrTest, FuncTest) {
  // *
    UniquePtr<int> con1(new int(111));
    EXPECT_TRUE(*con1 == 111);
    *con1 = 222;
    EXPECT_TRUE(*con1 == 222);
    // ->
    UniquePtr<T> con2(new T);
    EXPECT_TRUE(con2->t == 1111);
    // Get, GetDeleter
    UniquePtr<int, DerivedDelete> con3(new int(333));
    EXPECT_TRUE(*con3.Get() == 333);
    EXPECT_TRUE( (con3.GetDeleter()==DerivedDelete()) );
    // reset, realse
    int* ptr = con3.Release();
    EXPECT_TRUE(*ptr == 333);
    EXPECT_TRUE(con3.Get() == nullptr);
    con3.Reset(ptr);
    EXPECT_TRUE(con3.Get() == ptr);
    EXPECT_TRUE(*con3 == 333);
    // swap
    UniquePtr<int, DerivedDelete> con4(new int(444));
    con3.Swap(con4);
    EXPECT_TRUE(*con3 == 444);
    EXPECT_TRUE(*con4 == 333);
}

/* 数组特化版本 */
TEST_F(UniquePtrTest, ArrTest) {
    UniquePtr<Base>(new Base);
    UniquePtr<Base>(new Derived);
    UniquePtr<Base[]> a(new Base[2]);
    // 匹配到delete的构造函数
    //UniquePtr<Base[]> b(new Derived[2]);
    BaseArrDelete d;
    UniquePtr<Base[], BaseArrDelete&> b(new Base[2], d);
}

TEST_F(UniquePtrTest, MakeUniptrTest) {
    auto a = spwptr::makeUnique<Base>();
    auto b = spwptr::makeUnique<Base[]>(2);
    // delete 
    //auto c = spwptr::makeUnique<Base[2]>();
    auto d = spwptr::makeUnique<Base>(1,2,3);
    EXPECT_TRUE(d->base_==1);
    EXPECT_TRUE(d->base3_==3);
}
